package br.brpv.silvestrin.updater;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.*;
import android.util.Log;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


public class UpdaterService extends Service {
    public Context context;

    public static final int MSG_UPDATE_APP = 4;
    public static final int MSG_REGISTER_CLIENT = 1;
    public static final int MSG_UNREGISTER_CLIENT = 2;
    public static final int MSG_SET_VALUE = 3;
    public static final int MSG_UPDATE_CHECK_DONE = 5;
    public static final int MSG_UPDATE_CHECK_ERRO = 6;

    /** Keeps track of all current registered clients. */
    ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    /** Holds last value set by a client. */
    int mValue = 0;

    private static ArrayList<App> mApps = new ArrayList<App>();

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    private Timer timer;

    @Override
    public void onCreate() {
        context = this;

        timer = new Timer();

        timer.scheduleAtFixedRate(new CheckForUpdatesTimer(),0, 60*60*1000);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("LocalService", "Received start id " + startId + ": " + intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_CLIENT:
                    mClients.add(msg.replyTo);
                    new CheckForUpdatesAsyncTask().execute();
                    break;
                case MSG_UNREGISTER_CLIENT:
                    mClients.remove(msg.replyTo);
                    break;
                case MSG_SET_VALUE:
                    mValue = msg.arg1;
                    sendMessageToClients(MSG_SET_VALUE);
                    break;
                case MSG_UPDATE_APP:
                    mValue = msg.arg1;
                    new CheckForUpdatesAsyncTask().execute();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private void sendMessageToClients(int msgCode) {
        for (int i=mClients.size()-1; i>=0; i--) {
            try {
                mClients.get(i).send(Message.obtain(null,
                        msgCode, 0, 0));
            } catch (RemoteException e) {
                // The client is dead.  Remove it from the list;
                // we are going through the list from back to front
                // so this is safe to do inside the loop.
                mClients.remove(i);
            }
        }
    }

    class CheckForUpdatesTimer extends TimerTask {

        public void run(){
            checkForUpdates();
        }

    }

    private class CheckForUpdatesAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... voids) {
            checkForUpdates();

            return null;
        }
    }

    private void checkForUpdates(){
        String appsVersionFile = "SilvestrinApps.txt";
        ArrayList<App> listOfApp = new ArrayList<App>();

        try {
            System.out.println("Start Update!!");
            URL url = new URL("https://dl.dropboxusercontent.com/u/1472514/" + appsVersionFile);
            //System.out.println("BLABLA" + url.getFile());
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setUseCaches(false);
            BufferedReader bufferReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String StringBuffer;
            String stringText = "";
            while ((StringBuffer = bufferReader.readLine()) != null) {
                stringText += (StringBuffer + "\n");
                String tokens[] =  StringBuffer.split(";");
                listOfApp.add(new App(tokens[0], tokens[1], tokens[2]));
            }
            bufferReader.close();
            checkIsAppsAreUptodate(listOfApp);
            UpdaterService.setmApps(listOfApp);

            sendMessageToClients(MSG_UPDATE_CHECK_DONE);

            System.out.println(stringText);

        } catch (MalformedURLException e) {
            sendMessageToClients(MSG_UPDATE_CHECK_ERRO);
            e.printStackTrace();
        } catch (ProtocolException e) {
            sendMessageToClients(MSG_UPDATE_CHECK_ERRO);
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            sendMessageToClients(MSG_UPDATE_CHECK_ERRO);
            e.printStackTrace();
        } catch (IOException e) {
            sendMessageToClients(MSG_UPDATE_CHECK_ERRO);
            e.printStackTrace();
        }

        finally {


        }

    }

    private void checkIsAppsAreUptodate(ArrayList<App> listOfApp) {
        List<AppInfo> appsInfo = getInstalledApps();

        for(App app : listOfApp){
            app.setUptodate(isAppUptodate(app, appsInfo));
        }
    }

    private boolean isAppUptodate(App app, List<AppInfo> appsInfo) {
        for(AppInfo info : appsInfo){
            if(info.appname.equals(app.getName())){
                if(info.getVersionName().equals(app.getVersioname())) {
                    return true;
                } else {
                    break;
                }
            }
        }
        showUpdateNotification(app.getName());
        return false;
    }

    private void showUpdateNotification(String appName) {
        // Prepare intent which is triggered if the
        // notification is selected

        Intent intent = new Intent(this, Updater.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);

        // Build notification
        // Actions are just fake
        Notification noti = new Notification.Builder(this)
                .setContentTitle("Atualisar Aplicativo")
                .setContentText("O aplicativo " + appName + " possui uma atualisação.").setSmallIcon(android.R.drawable.ic_media_play)
                .setContentIntent(pIntent)
                .getNotification();


        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        // Hide the notification after its selected
        noti.flags |= Notification.FLAG_AUTO_CANCEL;

        notificationManager.notify(0, noti);
    }

    public static ArrayList<App> getmApps() {
        return mApps;
    }

    public static void setmApps(ArrayList<App> mApps) {
        UpdaterService.mApps = mApps;

    }

    private ArrayList<AppInfo> getInstalledApps() {
        ArrayList<AppInfo> res = new ArrayList<AppInfo>();

        List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);

        for(int i=0;i<packs.size();i++) {
            PackageInfo p = packs.get(i);
            if ((p.versionName == null)) {
                continue ;
            }
            AppInfo newInfo = new AppInfo();
            newInfo.appname = p.applicationInfo.loadLabel(getPackageManager()).toString();
            newInfo.pname = p.packageName;
            newInfo.versionName = p.versionName;
            newInfo.versionCode = p.versionCode;
            res.add(newInfo);
        }

        return res;
    }
}
